#pragma once

#include<iostream>
#include<string>
#include<queue>
#include<pthread.h>

const int default_cap = 5;
template<class T>
class BlockQueue
{
private:
    bool isFull(){return _bp.size() >= _cap}
    bool isEmpty(){return _bp.empty()}
public:
    BlockQueue(int cap = default_cap)
    :_cap(cap),_Csleep_num(0),_Psleep_num(0)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_full_cond,nullptr);
        pthread_cond_init(&_empty_cond,nullptr);
    }

    void EnQueue(const T& in)
    {
        pthread_mutex_lock(&_mutex);
        while(isFull())
        {
            _Psleep_num++;
            std::cout<<"生产者进入等待队列:"<<_Psleep_num<<std::endl;
            pthread_cond_wait(&_full_cond,&_mutex);
            _Psleep_num--;
        }

        _bp.push(in);
        if(_Csleep_num > 0)
        {
            std::cout<<"唤醒消费者"<<std::endl;
            pthread_cond_signal(&_empty_cond);
        }

        pthread_mutex_unlock(&_mutex);
    }

    T Pop()
    {
        pthread_mutex_lock(&_mutex);
        while(isEmpty())
        {
            _Csleep_num++;
            std::cout<<"消费者进入等待队列:"<<_Csleep_num<<std::endl;
            pthread_cond_wait(&_empty_cond,&_mutex);
            _Csleep_num--;
        }

        T ret = _bp.front();
        _bp.pop();

        if(_Psleep_num > 0)
        {
            std::cout<<"唤醒生产者"<<std::endl;
            pthread_cond_signal(&_full_cond);
        }

        pthread_mutex_unlock(&_mutex);
        return ret;
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&_full_cond);
        pthread_cond_destroy(&_empty_cond);
    }
private:
    std::queue<T> _bq;
    int _cap;

    pthread_mutex_t _mutex;
    pthread_cond_t _full_cond;
    pthread_cond_t _empty_cond;

    int _Csleep_num;
    int _Psleep_num;
};